package com.lutzyt.delivery.config;

import com.alibaba.fastjson.JSON;
import com.lutzyt.delivery.service.impl.UserDetailsServiceImpl;
import com.lutzyt.delivery.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 安全管理
 *
 * @author zyt
 */
@Slf4j
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {


//  private VerifyCodeFilter verifyCodeFilter;

  private UserDetailsService userDetailsService;

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    // http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);

    http.formLogin()
        .loginPage("/loginPage")
        .usernameParameter("username")
        .passwordParameter("password")
        .loginProcessingUrl("/api/login")
        .successHandler((request, response, authentication) -> {
          log.info("登录成功");
          request.setCharacterEncoding("utf-8");
          response.setCharacterEncoding("utf-8");
          response.getWriter().write(JSON.toJSONString(Result.success()));
        })
        .failureHandler((request, response, e) -> {
          log.info("登录失败");
          request.setCharacterEncoding("utf-8");
          response.setCharacterEncoding("utf-8");
          response.getWriter().write(JSON.toJSONString(Result.fail("登录失败")));
        })
        .permitAll()
        .and().logout()
        .logoutUrl("/api/logout")
        .logoutSuccessUrl("/loginPage")
        .and().authorizeRequests()
        .antMatchers("/", "/loginPage", "/api/home", "/api/login", "/getAuthCode").permitAll()
        .antMatchers("/**/*.js", "/**/*.css", "/**/*.png", "/layui/**/*", "/**/*.jpg", "/**/*.ico").permitAll()
        .anyRequest().permitAll() // TODO: 此处应该是限制为登录后
        .and()
        .exceptionHandling()
        .authenticationEntryPoint((request, response, e) -> {
          log.info("未登录" + e);
          request.setCharacterEncoding("utf-8");
          response.setCharacterEncoding("utf-8");
          response.getWriter().write(JSON.toJSONString(Result.unAuthenticated()));
        })
        .accessDeniedHandler((request, response, e) -> {
          log.info("无权限" + e);
          request.setCharacterEncoding("utf-8");
          response.setCharacterEncoding("utf-8");
          response.getWriter().write(JSON.toJSONString(Result.unAuthorized()));
        });
    // 取消csrf防护
    http.csrf().disable();
    // 同源跨域
    http.headers().frameOptions().sameOrigin();
  }

  @Bean
  public BCryptPasswordEncoder passwordEncoder() {
    return new BCryptPasswordEncoder();
  }

  @Bean
  public WebMvcConfigurer corsConfigurer() {
    return new WebMvcConfigurer() {
      @Override
      public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").
            allowedOrigins("*"). //允许跨域的域名，可以用*表示允许任何域名使用
            allowedMethods("*"). //允许任何方法（post、get等）
            allowedHeaders("*"). //允许任何请求头
            allowCredentials(true). //带上cookie信息
            exposedHeaders(HttpHeaders.SET_COOKIE).maxAge(3600L); //maxAge(3600)表明在3600秒内，不需要再发送预检验请求，可以缓存该结果
      }
    };
  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
        .userDetailsService(userDetailsService)
        .and()
        .inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
        .withUser("admin")
        .password(new BCryptPasswordEncoder().encode("admin"))
        .roles("ADMIN")
        .and()
        .withUser("user")
        .password(new BCryptPasswordEncoder().encode("user"))
        .roles("USER");
  }

  @Autowired
  public void setUserDetailsService(UserDetailsServiceImpl userDetailsService) {
    this.userDetailsService = userDetailsService;
  }

  //  @Autowired
//  public void setVerifyCodeFilter(VerifyCodeFilter verifyCodeFilter) {
//    this.verifyCodeFilter = verifyCodeFilter;
//  }
}


